﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO.MemoryMappedFiles;
using System.Threading;
using System.Windows.Forms;
using CamPlug.Api;
using System.Linq;

namespace CamPlugManager
{
	public partial class MainForm : Form
	{
		MemoryMappedFile BitmapResponseMappedFile;

		public MainForm()
		{
			InitializeComponent();
			this.BitmapResponseMappedFile = MemoryMappedFile.CreateNew(
				mapName: CamPlug.Shared.Consts.MemoryMapNames.BitmapResponseMappingName,
				capacity: CamPlug.Shared.Consts.Image.DataSize);

			foreach (IPluginFactory pluginFactory in PluginFactoryManager.PluginFactories)
			{
				var pluginFactoryItem = new PluginFactoryListBoxItem(pluginFactory);
				ListBoxAvailablePlugins.Items.Add(pluginFactoryItem);
			}
		}

		public IEnumerable<IPlugin> ActivePlugins
		{
			get
			{
				return BindingSourceActivePlugins.List.OfType<IPlugin>();
			}
		}

		public IPluginFactory SelectedPluginFactory
		{
			get
			{
				if (ListBoxAvailablePlugins.SelectedItem == null)
					return null;
				return (ListBoxAvailablePlugins.SelectedItem as PluginFactoryListBoxItem).PluginFactory;
			}
		}

		public IPlugin SelectedPlugin
		{
			get
			{
				return (IPlugin)BindingSourceActivePlugins.Current;
			}
		}

		void CreateFrame()
		{
			var bitmap = new Bitmap(width: 1024, height: 768);
			using (var canvas = Graphics.FromImage(bitmap))
			{
				canvas.FillRectangle(Brushes.Black, new Rectangle(0, 0, 1024, 768));
				ExecutePlugins(bitmap);
			}
			if (PictureBoxPreview.Image != null)
				PictureBoxPreview.Image.Dispose();
			PictureBoxPreview.Image = bitmap;

			using (var mutex = new Mutex(false, CamPlug.Shared.Consts.LockingNames.BitmapResponseMutexName))
			{
				try
				{
					mutex.WaitOne();
					WriteBitmapToMemoryMappedFile(bitmap);
				}
				finally
				{
					mutex.ReleaseMutex();
				}
			}
		}

		void ExecutePlugins(Bitmap bitmap)
		{
			foreach (IPlugin plugin in ActivePlugins)
				plugin.UpdateBitmap(bitmap);
		}

		void WriteBitmapToMemoryMappedFile(Bitmap bitmap)
		{
			using (var viewStream = BitmapResponseMappedFile.CreateViewStream())
				bitmap.Save(viewStream, ImageFormat.Bmp);
		}

		void ListBoxAvailablePlugins_SelectedIndexChanged(object sender, EventArgs e)
		{
			TextBoxAvailablePluginDescription.Text =
				SelectedPluginFactory == null ? "" : SelectedPluginFactory.Description;
			UpdatePluginArrangerControls();
		}

		void UpdatePluginArrangerControls()
		{
			ButtonAddPlugin.Enabled = SelectedPluginFactory != null;
			ButtonRemovePlugin.Enabled = SelectedPlugin != null;
			ButtonMovePluginUp.Enabled = false;
			if (DataGridActivePlugins.CurrentRow != null)
					ButtonMovePluginUp.Enabled = DataGridActivePlugins.CurrentRow.Index > 0;
			ButtonMovePluginDown.Enabled = false;
			if (DataGridActivePlugins.CurrentRow != null)
				ButtonMovePluginDown.Enabled = DataGridActivePlugins.CurrentRow.Index < BindingSourceActivePlugins.Count - 1;
		}

		void AddPlugin()
		{
			IPlugin plugin;
			if (!SelectedPluginFactory.TryCreatePlugin(out plugin))
			{
				MessageBox.Show("The plugin could not be created", "Error");
				return;
			}
			int rowIndex = BindingSourceActivePlugins.Add(plugin);
			BindingSourceActivePlugins.Position = rowIndex;
			UpdatePluginArrangerControls();
		}

		void RemovePlugin()
		{
			IPlugin currentPlugin = SelectedPlugin;
			if (currentPlugin == null)
				return;
			currentPlugin.ShuttingDown();
			BindingSourceActivePlugins.RemoveCurrent();
		}

		void ShowSelectedPluginProperties()
		{
			if (SelectedPlugin != null)
				SelectedPlugin.ShowPropertiesForm();
		}

		void MovePluginUp()
		{
			int newIndex = BindingSourceActivePlugins.Position - 1;
			object plugin = BindingSourceActivePlugins.Current;
			BindingSourceActivePlugins.RemoveCurrent();
			BindingSourceActivePlugins.Insert(newIndex, plugin);
			BindingSourceActivePlugins.Position = newIndex;
		}

		void MovePluginDown()
		{
			int newIndex = BindingSourceActivePlugins.Position + 1;
			object plugin = BindingSourceActivePlugins.Current;
			BindingSourceActivePlugins.RemoveCurrent();
			BindingSourceActivePlugins.Insert(newIndex, plugin);
			BindingSourceActivePlugins.Position = newIndex;
		}

		void TimerUpdateImage_Tick(object sender, EventArgs e)
		{
			CreateFrame();
		}

		void MainForm_Load(object sender, EventArgs e)
		{
			UpdatePluginArrangerControls();
		}

		void ButtonAddPlugin_Click(object sender, EventArgs e)
		{
			AddPlugin();
		}

		void DataGridActivePlugins_CellClick(object sender, DataGridViewCellEventArgs e)
		{
			if (e.ColumnIndex == ColumnShowPluginProperties.Index)
				ShowSelectedPluginProperties();
		}

		void BindingSourceActivePlugins_ListChanged(object sender, System.ComponentModel.ListChangedEventArgs e)
		{
			UpdatePluginArrangerControls();
		}

		void ButtonRemovePlugin_Click(object sender, EventArgs e)
		{
			RemovePlugin();
		}

		void DataGridActivePlugins_SelectionChanged(object sender, EventArgs e)
		{
			UpdatePluginArrangerControls();
		}

		void ButtonMovePluginUp_Click(object sender, EventArgs e)
		{
			MovePluginUp();
		}

		void ButtonMovePluginDown_Click(object sender, EventArgs e)
		{
			MovePluginDown();
		}

		void MainForm_FormClosed(object sender, FormClosedEventArgs e)
		{
			while (SelectedPlugin != null)
				RemovePlugin();
		}

		void MainForm_Shown(object sender, EventArgs e)
		{
			for (int columnIndex = DataGridActivePlugins.ColumnCount - 1; columnIndex > 1; columnIndex--)
				DataGridActivePlugins.Columns.RemoveAt(columnIndex);
		}


	}
}
